<!--
 * @author luguoxiang
 * @date 2022/9/17
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
-->
<template>
  <edit-container ref="containerRef" v-bind="containerConfig">
    <lg-form ref="formRef" v-loading="loading" :schema="schema" v-bind="formConfig">
      <template #component>
        <t-auto-complete
          v-model="data.component"
          style="width: 100%"
          :options="options"
          highlight-keyword
          placeholder="请输入页面组件"
          clearable
          @change="componentChange"
        />
      </template>
      <template #path>
        <t-auto-complete
          v-model="data.path"
          style="width: 100%"
          :options="pathOptions"
          highlight-keyword
          placeholder="请输入路径"
          clearable
        />
      </template>
      <template v-if="data.type === 1" #append>
        <t-space direction="vertical" style="'--lg-grid-min: 2;--lg-grid-max: 2'">
          <t-space>
            <t-button @click="createPermits">生成权限列表</t-button>
            <t-button v-if="permits.length" @click="addPermit">添加</t-button>
            <t-button v-if="permits.length" theme="default" @click="autoMatch">自动匹配接口权限</t-button>
          </t-space>
          <template v-if="permits.length">
            <t-table ref="tableRef" row-key="code" :columns="columns" :data="permits" bordered lazy-load>
              <template #actionbar="{ rowIndex }">
                <t-link theme="danger" @click="removePermit(rowIndex)">删除</t-link>
              </template>
            </t-table>
          </template>
        </t-space>
      </template>
    </lg-form>
  </edit-container>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Input, MessagePlugin, PrimaryTableCol } from 'tdesign-vue-next';
import { EditContainer, useEditContainer } from '@/components';
import { LgBizSelect, LgBizSelectProps, LgForm, syncLockLoad } from '@/soar';
import schema from './schema';
import api from './api';
import { COMPONENTS } from '@/constants';
import permitApi from '@/pages/auth/permit/api';

const emits = defineEmits(['ok']);

const components = [];
const containerRef = ref();
const formRef = ref();
const options = ref([]);
const permits = ref<{ title: string; code: string; permitIds: string[] }[]>([]);

const columns: PrimaryTableCol[] = [
  {
    title: '名称',
    colKey: 'title',
    width: 150,
    edit: {
      keepEditMode: true,
      defaultEditable: true,
      component: Input,
      onEdited: (context) => {
        permits.value.splice(context.rowIndex, 1, context.newRowData);
      },
      rules: [
        { required: true, message: '必填' },
        { validator: (val) => permits.value.filter((x: any) => x.title === val).length < 2, message: '名称重复' },
      ],
    },
  },
  {
    title: '编码',
    colKey: 'code',
    width: 300,
    edit: {
      keepEditMode: true,
      defaultEditable: true,
      component: Input,
      onEdited: (context) => {
        permits.value.splice(context.rowIndex, 1, context.newRowData);
      },
      rules: [
        { required: true, message: '必填' },
        { validator: (val) => permits.value.filter((x: any) => x.code === val).length < 2, message: '编码重复' },
      ],
    },
  },
  {
    title: '接口权限',
    colKey: 'permitIds',
    edit: {
      keepEditMode: true,
      defaultEditable: true,
      component: LgBizSelect,
      props: {
        data: (params) => syncLockLoad('load:permit', () => permitApi.query(params)),
        multiple: true,
        fields: 'id,name,code',
        search: true,
        labelField: '【${name}】${code}',
      } as LgBizSelectProps,
      onEdited: (context) => {
        permits.value.splice(context.rowIndex, 1, context.newRowData);
      },
    },
  },
  {
    title: '操作',
    colKey: 'actionbar',
    width: 60,
  },
];

let apiList = null;
function getApiList() {
  if (apiList) {
    return Promise.resolve(apiList);
  }
  return syncLockLoad('load:permit', () =>
    permitApi.query({ $soarQuery: { fields: 'id,name,code' }, queryType: 'list', pageSize: 99999 }),
  ).then((res) => {
    apiList = res.list.map((x) => ({ value: x.id, codes: x.code.split('/').reverse() }));
    return apiList;
  });
}

function getPermitIds(code: string) {
  const cs = code.split(/[_:-\\/]/).reverse();
  const filter = (list, index, str) => {
    const rs = list.filter((x) => x.codes[index] === str);
    if (rs.length === 0) {
      return list;
    }
    if (rs.length === 1) {
      return rs;
    }
    index += 1;
    if (index >= cs.length) {
      return rs;
    }
    return filter(rs, index, cs[index]);
  };

  return getApiList().then((res) => {
    const ls = filter(res, 0, cs[0]);
    if (ls.length === 1) {
      return ls.map((y) => y.value);
    }
    return [];
  });
}

/**
 * 生成权限列表
 */
async function createPermits() {
  const base = data.value.code || data.value.path;
  if (base) {
    permits.value = [
      { title: '查询', code: `${base}/query`, permitIds: await getPermitIds(`${base}/query`) },
      { title: '新增', code: `${base}/create`, permitIds: await getPermitIds(`${base}/create`) },
      { title: '更新', code: `${base}/update`, permitIds: await getPermitIds(`${base}/update`) },
      { title: '删除', code: `${base}/remove`, permitIds: await getPermitIds(`${base}/remove`) },
      { title: '导入', code: `${base}/import`, permitIds: await getPermitIds(`${base}/import`) },
      { title: '导出', code: `${base}/export`, permitIds: await getPermitIds(`${base}/export`) },
    ];
  } else {
    MessagePlugin.error('请输入权限码或路径');
  }
}

async function autoMatch() {
  for (const x of permits.value) {
    // eslint-disable-next-line no-await-in-loop
    x.permitIds = await getPermitIds(x.code);
  }
}

/**
 * 添加权限
 */
function addPermit() {
  const base = data.value.code || data.value.path;
  permits.value.push({ title: '', code: `${base}/`, permitIds: [] });
}

/**
 * 删除权限
 * @param index
 */
function removePermit(index) {
  permits.value.splice(index, 1);
}

const { containerConfig, formConfig, loading, open, data } = useEditContainer<any>({
  header: '菜单',
  containerRef,
  formRef,
  getData: (params: any) =>
    api.detail(params.id).then((res: any) => {
      permits.value = res.permits || [];
      return res;
    }),
  onOk: async ({ values, data, params, isUpdate, changed }) => {
    values.id = data.id;
    if (!values.code) {
      values.code = values.path;
    }
    values.permits = permits.value;
    await api.saveOrUpdate(values, isUpdate);
    emits('ok', values);
  },
  containerProps: {
    width: '1200px',
  },
  onOpen(params: any) {
    permits.value = [];
    options.value = Object.keys(COMPONENTS);
  },
  data: { type: 1, status: 0, parentId: '0' },
});

const pathOptions = ref([]);
function componentChange(e) {
  pathOptions.value = [];
  if (e?.startsWith?.('pages/')) {
    const path = e.replace(/^pages\//, '').replace(/\.vue$/, '');
    const paths = path.split('/');
    for (let i = paths.length; i > 1; i--) {
      pathOptions.value.push(`/${paths.slice(0, i).join('/')}`);
    }
    for (let i = 1, len = paths.length - 1; i < len; i++) {
      pathOptions.value.push(`/${paths.slice(i).join('/')}`);
    }
    for (const x of paths) {
      pathOptions.value.push(`/${x}`);
    }
  }
}

defineExpose({ open });
</script>
